/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* includes (local) ----------------------------------------------------------*/
/* includes (standard library, system) ---------------------------------------*/
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* variables (extern) --------------------------------------------------------*/
/* variables (local) ---------------------------------------------------------*/
/* variables (global) --------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/

/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* includes (local) ----------------------------------------------------------*/
#include <vfs_fatfs.h>
#include <vfs.h>
/* includes (standard library, system) ---------------------------------------*/
#include <string.h>
#include <stdio.h>
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <x_module.h>
#include <hal_mtd.h>

/* defines -------------------------------------------------------------------*/

#define DISK_SECTOR_SIZE  (mtd->page_size)
#define DISK_SECTOR_COUNT (mtd->total_size / DISK_SECTOR_SIZE)

/* typedefs ------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* variables (extern) --------------------------------------------------------*/
/* variables (local) ---------------------------------------------------------*/
/* variables (global) --------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/

static DSTATUS __disk_dev_status(disk_dev_t *dev)
{
    return dev->state;
}

static DSTATUS __disk_dev_initialize(disk_dev_t *dev)
{
    hal_mtd_t *mtd = (hal_mtd_t *)dev->priv;

    if (mtd != NULL) {
        // init
        dev->state &= ~STA_NOINIT;
    }
    return dev->state;
}

static DRESULT __disk_dev_read(disk_dev_t *dev, BYTE *buf, DWORD sector, UINT count)
{
    hal_mtd_t *mtd = (hal_mtd_t *)dev->priv;

    if (hal_mtd_read_block(mtd, sector, count, buf) != 0) {
        return RES_ERROR;
    }

    return RES_OK;
}

static DRESULT __disk_dev_write(disk_dev_t *dev, const BYTE *buf, DWORD sector, UINT count)
{
    hal_mtd_t *mtd = (hal_mtd_t *)dev->priv;

    if (hal_mtd_write_block(mtd, sector, count, buf) != 0) {
        return RES_ERROR;
    }

    return RES_OK;
}

static DRESULT __disk_dev_ioctl(disk_dev_t *dev, BYTE cmd, void *buf)
{
    DRESULT res = RES_OK;
    hal_mtd_t *mtd = (hal_mtd_t *)dev->priv;

    switch (cmd) {
    case CTRL_SYNC:
        break;
    case GET_SECTOR_COUNT:
        *(DWORD *)buf = DISK_SECTOR_COUNT;
        break;
    case GET_SECTOR_SIZE:
        *(WORD *)buf = DISK_SECTOR_SIZE;
        break;
    case GET_BLOCK_SIZE:
        *(DWORD *)buf = DISK_SECTOR_SIZE;
        break;
    default:
        res = RES_PARERR;
        break;
    }
    return res;
}

static struct disk_ops dev_ops = {
    .initialize = __disk_dev_initialize,
    .status = __disk_dev_status,
    .read = __disk_dev_read,
    .write = __disk_dev_write,
    .ioctl = __disk_dev_ioctl,
};

/**
 * fatfs_mtd_init - initialize and mount MTD device as FAT filesystem
 * @mtd_name: the name of MTD device to open
 * @mount_path: the filesystem mount point path
 *
 * return: drive number on success, negative value on error
 *         -1: failed to open MTD device
 *         -2: failed to initialize fatfs
 *         -3: failed to mount fatfs
 */
int fatfs_mtd_init(const char *mtd_name, const char *mount_path)
{
    int8_t drive = -1;

    hal_mtd_t *mtd = hal_mtd_open(mtd_name);
    if (mtd == NULL) {
        return -1;
    }
    if (fatfs_init() != 0) {
        return -2;
    }
    if (fatfs_mount(mount_path, &dev_ops, (uintptr_t)mtd, (uint8_t *)&drive) != 0) {
        return -3;
    }

    return drive;
}

/**
 * fatfs_mtd_exit - unmount and deinitialize MTD FAT filesystem
 * @drive: the drive number to unmount
 * @mount_path: the filesystem mount point path
 *
 * return: 0 on success, negative value on error
 */
int fatfs_mtd_exit(int drive, const char *mount_path)
{
    if (drive < 0) {
        return -1;
    }
    if (fatfs_unmount(mount_path, drive) != 0) {
        return -1;
    }
    fatfs_exit();
    // TODO: release private data (close mtd)
    return 0;
}

DWORD get_fattime(void)
{
    return 0;
}
